<?php
/*
 * Copyright (c) 2009 Tom Smith (tom@takeontom.com).
 * 
 * Distributed under the terms of the GNU Lesser General Public License.
 * 
 * ---------------------------------------------------------------------------------
 * 
 * This file is part of Seraph PHP Framework.
 *
 * Seraph PHP Framework is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Seraph PHP Framework is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Seraph PHP Framework.  If not, see <http://www.gnu.org/licenses/>.
*/


/**
 * Extended from EntityContainer to use the neat key hashing.
 * 
 * @author Tom
 *
 */
class EntityCache extends EntityContainer	{
	/**
	 * Get an entity from the system.
	 * 
	 * If the entity is not in the cache then will try to load
	 * the entity from the database, add to cache and then return.
	 * 
	 * Can either pass a classname (string) or an instance of an Entity
	 * object as the type param. 
	 * 
	 * If the key specified is not a primary key, then this will not check whether
	 * the object is in cache, instead will load them from the database and then add
	 * to the cache.  
	 * 
	 * @param $type
	 * @param $key
	 * @return Entity | EntityContainer
	 */
	public function getEntity($type, array $key = array())	{
		//allow the passing of entities or strings
		if ($type instanceof Entity)	{
			$e = $type;
		} else {
			$e = new $type;
		}
		
		$pkeyMatch = $e->doesPrimaryKeyMatch($key);
		//var_dump($pkeyMatch);
		if ($pkeyMatch)	{
			//the key specified is a primary key, so check the cache
			if ($this->isEntityInContainer($type, $key))	{
				return $this->getEntityFromContainer($type, $key);
			}
		}
		
		$entity = $this->getEntityFromDatabase($type, $key);
		
		
		//returned value might either be a single entity or an entity container
		//check whether the entity is in the cache before returning to ensure that
		//each entity only exists once 
		if ($entity instanceof Entity)	{
			if ($this->isEntityInContainer($type, $entity->getPrimaryKeyValue()))	{
				//is in cache
				return $this->getEntityFromContainer($type, $entity->getPrimaryKeyValue());
			}
			
			$this->addEntity($entity);
			return $entity;
		} elseif ($entity instanceof EntityContainer)	{
			$out = new EntityContainer();
			foreach($entity as $anEntity)	{
				if ($this->isEntityInContainer($type, $anEntity->getPrimaryKeyValue()))	{
					//is in cache
					$anEntity = $this->getEntityFromContainer($type, $entity->getPrimaryKeyValue());
				}
				$out->addEntity($anEntity);
			}
			return $out;
		}
		
		return null;
		
	}
	
	protected function getEntityFromDatabase($type, array $key)	{
		if ($type instanceof Entity)	{
			$type = get_class($type);
		}
		if (!class_exists($type))	{
			throw new InvalidArgumentException('Unable to get entity as requested class (' . $type . ') does not exist.');
		}
		$e = new $type;
		$dao = $e->getDAO();
		$e = $dao->get($e, $key);
		if (!$e)	{
			throw new RuntimeException('Unable to get entity from DAO.');
		}
		return $e;
	}
}
?>